/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.IO;
using System.Text;
using System.Xml;

using Anculus.Core;

//using LibMimic;

namespace Galaxium.Protocol.Msn
{
	public abstract class P2PWebcamBase : AbstractMsnP2PSessionApplication
	{
		public event EventHandler<WebcamFrameReceivedEventArgs> FrameReceived;
		
		private MsnConversation _conversation;
		private WebcamConnection _connection;
		//private MimicDecoder _decoder;
		
		public P2PWebcamBase (MsnP2PSession p2pSession)
			: base (p2pSession)
		{
			//TODO: What's this for? It's a GUID, but I've no idea why it's there
			//string context = MsnEncodingUtility.Base64DecodeSafe (P2PSession.Invite.MIMEBody["Context"].Value, Encoding.Unicode);
		}
		
		protected WebcamConnection Connection
		{
			get { return _connection; }
		}
		
		protected MsnConversation Conversation
		{
			get
			{
				if (_conversation == null)
				{
					//TODO: will the MsnP2PSession always be using a switchboard?
					_conversation = (Session.Conversations as MsnConversationManager).GetConversation (P2PSession.Bridge as SBConnection);
					
					if (_conversation == null)
					{
						_conversation = new MsnConversation (P2PSession.Bridge as SBConnection);
						Session.Conversations.Add (_conversation);
					}
				}
				
				return _conversation;
			}
		}
		
		protected abstract bool Producer { get; }

		public override bool CheckInvite (SLPRequestMessage invite)
		{
			return base.CheckInvite (invite);
		}
		
		public override string CreateInviteContext ()
		{
			throw new NotImplementedException ();
		}
		
		public override bool ProcessMessage (IMsnP2PBridge bridge, P2PMessage msg)
		{
			try
			{
				// Try to decode the payload as unicode
				string str = Encoding.Unicode.GetString (msg.Payload, 10, msg.Payload.Length - 10).Replace ("\0", "").Trim ();
				
				Log.Debug ("Received {0}", str);
				
				if (str.StartsWith ("syn"))
				{
					// Send syn
					SendSIP ("syn");
					return true;
				}
				else if (str.StartsWith ("ack"))
				{
					// Send ack
					SendSIP ("ack");
					return true;
				}
				else if (str.StartsWith ("receivedViewerData"))
				{
					_connection.Connect ();
					
					return true;
				}
				else
				{
					XmlDocument xml = new XmlDocument ();
					xml.LoadXml (str);
					
					CreateConnection (xml.DocumentElement);
					
					SendSIP (_connection.LocalXml);
					
					return true;
				}
			}
			catch (Exception) { }
			
			// Unknown message, log it to make debugging easier
			// We should remove this once we're happy about how the webcam works
			Log.Debug ("{0}", msg.ToString (false));
			
#if debug
			return false;
#else
			// If we're not debugging then we should try to continue even if we don't understand this message
			return true;
#endif
		}
		
		protected virtual void SendSIP (string cmd)
		{
			byte[] cmdData = Encoding.Unicode.GetBytes (cmd + '\0');
			
			MemoryStream stream = new MemoryStream ();
			BinaryWriter writer = new BinaryWriter (stream);
			
			writer.Write ((byte)0x80);
			writer.Write ((Int16)new Random ().Next (0, 65000));
			writer.Write (new byte[] { 0x01, 0x08, 0x00 });
			writer.Write ((Int32)cmdData.Length);
			writer.Write (cmdData);
			
			byte[] data = new byte[stream.Length];
			stream.Seek (0, SeekOrigin.Begin);
			stream.Read (data, 0, data.Length);
				
			writer.Close ();
			
			P2PMessage msg = new P2PMessage (Session);
			msg.Payload = data;
			
			Send (msg, delegate { });
		}
		
		protected virtual void CreateConnection (XmlElement xml)
		{
			Log.Debug ("Creating webcam connection");
					
			_connection = new WebcamConnection (Remote, xml);
			_connection.FrameReceived += ConnectionFrameReceived;
		}
		
		void ConnectionFrameReceived (object sender, WebcamFrameReceivedEventArgs args)
		{
			/*if (_decoder == null)
				_decoder = new MimicDecoder ();
			
			// libmimic gives us the data in RGB 24-bpp packed pixel top-down format
			byte[] decoded = _decoder.Decode (args.Data);
			
			if (FrameReceived != null)
				FrameReceived (this, new WebcamFrameReceivedEventArgs (decoded, _decoder.Width, _decoder.Height));*/
		}
	}
}
